home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 1 Issue 2
/
PDCD-1 - Issue 02.iso
/
_utilities
/
utilities
/
001
/
meschach
/
!Meschach
/
c
/
sprow
< prev
next >
Wrap
Text File
|
1994-01-13
|
18KB
|
715 lines
/**************************************************************************
**
** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
**
** Meschach Library
**
** This Meschach Library is provided "as is" without any express
** or implied warranty of any kind with respect to this software.
** In particular the authors shall not be liable for any direct,
** indirect, special, incidental or consequential damages arising
** in any way from use of the software.
**
** Everyone is granted permission to copy, modify and redistribute this
** Meschach Library, provided:
** 1. All copies contain this copyright notice.
** 2. All modified copies shall carry a notice stating who
** made the last modification and the date of such modification.
** 3. No charge is made for this software or works derived from it.
** This clause shall not be construed as constraining other software
** distributed on the same medium as this software, nor is a
** distribution fee considered a charge.
**
***************************************************************************/
/*
Sparse rows package
See also: sparse.h, matrix.h
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "sparse.h"
static char rcsid[] = "$Id: sprow.c,v 1.1 1994/01/13 05:35:36 des Exp $";
#define MINROWLEN 10
/* sprow_dump - prints relevant information about the sparse row r */
void sprow_dump(fp,r)
FILE *fp;
SPROW *r;
{
int j_idx;
row_elt *elts;
fprintf(fp,"SparseRow dump:\n");
if ( ! r )
{ fprintf(fp,"*** NULL row ***\n"); return; }
fprintf(fp,"row: len = %d, maxlen = %d, diag idx = %d\n",
r->len,r->maxlen,r->diag);
fprintf(fp,"element list @ 0x%lx\n",(long)(r->elt));
if ( ! r->elt )
{
fprintf(fp,"*** NULL element list ***\n");
return;
}
elts = r->elt;
for ( j_idx = 0; j_idx < r->len; j_idx++, elts++ )
fprintf(fp,"Col: %d, Val: %g, nxt_row = %d, nxt_idx = %d\n",
elts->col,elts->val,elts->nxt_row,elts->nxt_idx);
fprintf(fp,"\n");
}
/* sprow_idx -- get index into row for a given column in a given row
-- return -1 on error
-- return -(idx+2) where idx is index to insertion point */
int sprow_idx(r,col)
SPROW *r;
int col;
{
register int lo, hi, mid;
int tmp;
register row_elt *r_elt;
/*******************************************
if ( r == (SPROW *)NULL )
return -1;
if ( col < 0 )
return -1;
*******************************************/
r_elt = r->elt;
if ( r->len <= 0 )
return -2;
/* try the hint */
/* if ( hint >= 0 && hint < r->len && r_elt[hint].col == col )
return hint; */
/* otherwise use binary search... */
/* code from K&R Ch. 6, p. 125 */
lo = 0; hi = r->len - 1; mid = lo;
while ( lo <= hi )
{
mid = (hi + lo)/2;
if ( (tmp=r_elt[mid].col-col) > 0 )
hi = mid-1;
else if ( tmp < 0 )
lo = mid+1;
else /* tmp == 0 */
return mid;
}
tmp = r_elt[mid].col - col;
if ( tmp > 0 )
return -(mid+2); /* insert at mid */
else /* tmp < 0 */
return -(mid+3); /* insert at mid+1 */
}
/* sprow_get -- gets, initialises and returns a SPROW structure
-- max. length is maxlen */
SPROW *sprow_get(maxlen)
int maxlen;
{
SPROW *r;
if ( maxlen < 0 )
error(E_NEG,"sprow_get");
r = NEW(SPROW);
if ( ! r )
error(E_MEM,"sprow_get");
else if (mem_info_is_on()) {
mem_bytes(TYPE_SPROW,0,sizeof(SPROW));
mem_numvar(TYPE_SPROW,1);
}
r->elt = NEW_A(maxlen,row_elt);
if ( ! r->elt )
error(E_MEM,"sprow_get");
else if (mem_info_is_on()) {
mem_bytes(TYPE_SPROW,0,maxlen*sizeof(row_elt));
}
r->len = 0;
r->maxlen = maxlen;
r->diag = -1;
return r;
}
/* sprow_xpd -- expand row by means of realloc()
-- type must be TYPE_SPMAT if r is a row of a SPMAT structure,
otherwise it must be TYPE_SPROW
-- returns r */
SPROW *sprow_xpd(r,n,type)
SPROW *r;
int n,type;
{
int newlen;
if ( ! r ) {
r = NEW(SPROW);
if (! r )
error(E_MEM,"sprow_xpd");
else if ( mem_info_is_on()) {
if (type != TYPE_SPMAT && type != TYPE_SPROW)
warning(WARN_WRONG_TYPE,"sprow_xpd");
mem_bytes(type,0,sizeof(SPROW));
if (type == TYPE_SPROW)
mem_numvar(type,1);
}
}
if ( ! r->elt )
{
r->elt = NEW_A((unsigned)n,row_elt);
if ( ! r->elt )
error(E_MEM,"sprow_xpd");
else if (mem_info_is_on()) {
mem_bytes(type,0,n*sizeof(row_elt));
}
r->len = 0;
r->maxlen = n;
return r;
}
if ( n <= r->len )
newlen = max(2*r->len + 1,MINROWLEN);
else
newlen = n;
if ( newlen <= r->maxlen )
{
MEM_ZERO((char *)(&(r->elt[r->len])),
(newlen-r->len)*sizeof(row_elt));
r->len = newlen;
}
else
{
if (mem_info_is_on()) {
mem_bytes(type,r->maxlen*sizeof(row_elt),
newlen*sizeof(row_elt));
}
r->elt = RENEW(r->elt,newlen,row_elt);
if ( ! r->elt )
error(E_MEM,"sprow_xpd");
r->maxlen = newlen;
r->len = newlen;
}
return r;
}
/* sprow_resize -- resize a SPROW variable by means of realloc()
-- n is a new size
-- returns r */
SPROW *sprow_resize(r,n,type)
SPROW *r;
int n,type;
{
if (n < 0)
error(E_NEG,"sprow_resize");
if ( ! r )
return sprow_get(n);
if (n == r->len)
return r;
if ( ! r->elt )
{
r->elt = NEW_A((unsigned)n,row_elt);
if ( ! r->elt )
error(E_MEM,"sprow_resize");
else if (mem_info_is_on()) {
mem_bytes(type,0,n*sizeof(row_elt));
}
r->maxlen = r->len = n;
return r;
}
if ( n <= r->maxlen )
r->len = n;
else
{
if (mem_info_is_on()) {
mem_bytes(type,r->maxlen*sizeof(row_elt),
n*sizeof(row_elt));
}
r->elt = RENEW(r->elt,n,row_elt);
if ( ! r->elt )
error(E_MEM,"sprow_resize");
r->maxlen = r->len = n;
}
return r;
}
/* release a row of a matrix */
int sprow_free(r)
SPROW *r;
{
if ( ! r )
return -1;
if (mem_info_is_on()) {
mem_bytes(TYPE_SPROW,sizeof(SPROW),0);
mem_numvar(TYPE_SPROW,-1);
}
if ( r->elt )
{
if (mem_info_is_on()) {
mem_bytes(TYPE_SPROW,r->maxlen*sizeof(row_elt),0);
}
free((char *)r->elt);
}
free((char *)r);
return 0;
}
/* sprow_merge -- merges r1 and r2 into r_out
-- cannot be done in-situ
-- type must be SPMAT or SPROW depending on
whether r_out is a row of a SPMAT structure
or a SPROW variable
-- returns r_out */
SPROW *sprow_merge(r1,r2,r_out,type)
SPROW *r1, *r2, *r_out;
int type;
{
int idx1, idx2, idx_out, len1, len2, len_out;
row_elt *elt1, *elt2, *elt_out;
if ( ! r1 || ! r2 )
error(E_NULL,"sprow_merge");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
if ( r1 == r_out || r2 == r_out )
error(E_INSITU,"sprow_merge");
/* Initialise */
len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
idx1 = idx2 = idx_out = 0;
elt1 = r1->elt; elt2 = r2->elt; elt_out = r_out->elt;
while ( idx1 < len1 || idx2 < len2 )
{
if ( idx_out >= len_out )
{ /* r_out is too small */
r_out->len = idx_out;
r_out = sprow_xpd(r_out,0,type);
len_out = r_out->len;
elt_out = &(r_out->elt[idx_out]);
}
if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
{
elt_out->col = elt1->col;
elt_out->val = elt1->val;
if ( elt1->col == elt2->col && idx2 < len2 )
{ elt2++; idx2++; }
elt1++; idx1++;
}
else
{
elt_out->col = elt2->col;
elt_out->val = elt2->val;
elt2++; idx2++;
}
elt_out++; idx_out++;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_copy -- copies r1 and r2 into r_out
-- cannot be done in-situ
-- type must be SPMAT or SPROW depending on
whether r_out is a row of a SPMAT structure
or a SPROW variable
-- returns r_out */
SPROW *sprow_copy(r1,r2,r_out,type)
SPROW *r1, *r2, *r_out;
int type;
{
int idx1, idx2, idx_out, len1, len2, len_out;
row_elt *elt1, *elt2, *elt_out;
if ( ! r1 || ! r2 )
error(E_NULL,"sprow_copy");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
if ( r1 == r_out || r2 == r_out )
error(E_INSITU,"sprow_copy");
/* Initialise */
len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
idx1 = idx2 = idx_out = 0;
elt1 = r1->elt; elt2 = r2->elt; elt_out = r_out->elt;
while ( idx1 < len1 || idx2 < len2 )
{
while ( idx_out >= len_out )
{ /* r_out is too small */
r_out->len = idx_out;
r_out = sprow_xpd(r_out,0,type);
len_out = r_out->maxlen;
elt_out = &(r_out->elt[idx_out]);
}
if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
{
elt_out->col = elt1->col;
elt_out->val = elt1->val;
if ( elt1->col == elt2->col && idx2 < len2 )
{ elt2++; idx2++; }
elt1++; idx1++;
}
else
{
elt_out->col = elt2->col;
elt_out->val = 0.0;
elt2++; idx2++;
}
elt_out++; idx_out++;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_mltadd -- sets r_out <- r1 + alpha.r2
-- cannot be in situ
-- only for columns j0, j0+1, ...
-- type must be SPMAT or SPROW depending on
whether r_out is a row of a SPMAT structure
or a SPROW variable
-- returns r_out */
SPROW *sprow_mltadd(r1,r2,alpha,j0,r_out,type)
SPROW *r1, *r2, *r_out;
double alpha;
int j0, type;
{
int idx1, idx2, idx_out, len1, len2, len_out;
row_elt *elt1, *elt2, *elt_out;
if ( ! r1 || ! r2 )
error(E_NULL,"sprow_mltadd");
if ( r1 == r_out || r2 == r_out )
error(E_INSITU,"sprow_mltadd");
if ( j0 < 0 )
error(E_BOUNDS,"sprow_mltadd");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
/* Initialise */
len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
/* idx1 = idx2 = idx_out = 0; */
idx1 = sprow_idx(r1,j0);
idx2 = sprow_idx(r2,j0);
idx_out = sprow_idx(r_out,j0);
idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
elt1 = &(r1->elt[idx1]);
elt2 = &(r2->elt[idx2]);
elt_out = &(r_out->elt[idx_out]);
while ( idx1 < len1 || idx2 < len2 )
{
if ( idx_out >= len_out )
{ /* r_out is too small */
r_out->len = idx_out;
r_out = sprow_xpd(r_out,0,type);
len_out = r_out->maxlen;
elt_out = &(r_out->elt[idx_out]);
}
if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
{
elt_out->col = elt1->col;
elt_out->val = elt1->val;
if ( idx2 < len2 && elt1->col == elt2->col )
{
elt_out->val += alpha*elt2->val;
elt2++; idx2++;
}
elt1++; idx1++;
}
else
{
elt_out->col = elt2->col;
elt_out->val = alpha*elt2->val;
elt2++; idx2++;
}
elt_out++; idx_out++;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_add -- sets r_out <- r1 + r2
-- cannot be in situ
-- only for columns j0, j0+1, ...
-- type must be SPMAT or SPROW depending on
whether r_out is a row of a SPMAT structure
or a SPROW variable
-- returns r_out */
SPROW *sprow_add(r1,r2,j0,r_out,type)
SPROW *r1, *r2, *r_out;
int j0, type;
{
int idx1, idx2, idx_out, len1, len2, len_out;
row_elt *elt1, *elt2, *elt_out;
if ( ! r1 || ! r2 )
error(E_NULL,"sprow_add");
if ( r1 == r_out || r2 == r_out )
error(E_INSITU,"sprow_add");
if ( j0 < 0 )
error(E_BOUNDS,"sprow_add");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
/* Initialise */
len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
/* idx1 = idx2 = idx_out = 0; */
idx1 = sprow_idx(r1,j0);
idx2 = sprow_idx(r2,j0);
idx_out = sprow_idx(r_out,j0);
idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
elt1 = &(r1->elt[idx1]);
elt2 = &(r2->elt[idx2]);
elt_out = &(r_out->elt[idx_out]);
while ( idx1 < len1 || idx2 < len2 )
{
if ( idx_out >= len_out )
{ /* r_out is too small */
r_out->len = idx_out;
r_out = sprow_xpd(r_out,0,type);
len_out = r_out->maxlen;
elt_out = &(r_out->elt[idx_out]);
}
if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
{
elt_out->col = elt1->col;
elt_out->val = elt1->val;
if ( idx2 < len2 && elt1->col == elt2->col )
{
elt_out->val += elt2->val;
elt2++; idx2++;
}
elt1++; idx1++;
}
else
{
elt_out->col = elt2->col;
elt_out->val = elt2->val;
elt2++; idx2++;
}
elt_out++; idx_out++;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_sub -- sets r_out <- r1 - r2
-- cannot be in situ
-- only for columns j0, j0+1, ...
-- type must be SPMAT or SPROW depending on
whether r_out is a row of a SPMAT structure
or a SPROW variable
-- returns r_out */
SPROW *sprow_sub(r1,r2,j0,r_out,type)
SPROW *r1, *r2, *r_out;
int j0, type;
{
int idx1, idx2, idx_out, len1, len2, len_out;
row_elt *elt1, *elt2, *elt_out;
if ( ! r1 || ! r2 )
error(E_NULL,"sprow_sub");
if ( r1 == r_out || r2 == r_out )
error(E_INSITU,"sprow_sub");
if ( j0 < 0 )
error(E_BOUNDS,"sprow_sub");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
/* Initialise */
len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
/* idx1 = idx2 = idx_out = 0; */
idx1 = sprow_idx(r1,j0);
idx2 = sprow_idx(r2,j0);
idx_out = sprow_idx(r_out,j0);
idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
elt1 = &(r1->elt[idx1]);
elt2 = &(r2->elt[idx2]);
elt_out = &(r_out->elt[idx_out]);
while ( idx1 < len1 || idx2 < len2 )
{
if ( idx_out >= len_out )
{ /* r_out is too small */
r_out->len = idx_out;
r_out = sprow_xpd(r_out,0,type);
len_out = r_out->maxlen;
elt_out = &(r_out->elt[idx_out]);
}
if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
{
elt_out->col = elt1->col;
elt_out->val = elt1->val;
if ( idx2 < len2 && elt1->col == elt2->col )
{
elt_out->val -= elt2->val;
elt2++; idx2++;
}
elt1++; idx1++;
}
else
{
elt_out->col = elt2->col;
elt_out->val = -elt2->val;
elt2++; idx2++;
}
elt_out++; idx_out++;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_smlt -- sets r_out <- alpha*r1
-- can be in situ
-- only for columns j0, j0+1, ...
-- returns r_out */
SPROW *sprow_smlt(r1,alpha,j0,r_out,type)
SPROW *r1, *r_out;
double alpha;
int j0, type;
{
int idx1, idx_out, len1;
row_elt *elt1, *elt_out;
if ( ! r1 )
error(E_NULL,"sprow_smlt");
if ( j0 < 0 )
error(E_BOUNDS,"sprow_smlt");
if ( ! r_out )
r_out = sprow_get(MINROWLEN);
/* Initialise */
len1 = r1->len;
idx1 = sprow_idx(r1,j0);
idx_out = sprow_idx(r_out,j0);
idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
elt1 = &(r1->elt[idx1]);
r_out = sprow_resize(r_out,idx_out+len1-idx1,type);
elt_out = &(r_out->elt[idx_out]);
for ( ; idx1 < len1; elt1++,elt_out++,idx1++,idx_out++ )
{
elt_out->col = elt1->col;
elt_out->val = alpha*elt1->val;
}
r_out->len = idx_out;
return r_out;
}
/* sprow_foutput -- print a representation of r on stream fp */
void sprow_foutput(fp,r)
FILE *fp;
SPROW *r;
{
int i, len;
row_elt *e;
if ( ! r )
{
fprintf(fp,"SparseRow: **** NULL ****\n");
return;
}
len = r->len;
fprintf(fp,"SparseRow: length: %d\n",len);
for ( i = 0, e = r->elt; i < len; i++, e++ )
fprintf(fp,"Column %d: %g, next row: %d, next index %d\n",
e->col, e->val, e->nxt_row, e->nxt_idx);
}
/* sprow_set_val -- sets the j-th column entry of the sparse row r
-- Note: destroys the usual column & row access paths */
double sprow_set_val(r,j,val)
SPROW *r;
int j;
double val;
{
int idx, idx2, new_len;
if ( ! r )
error(E_NULL,"sprow_set_val");
idx = sprow_idx(r,j);
if ( idx >= 0 )
{ r->elt[idx].val = val; return val; }
/* else */ if ( idx < -1 )
{
/* shift & insert new value */
idx = -(idx+2); /* this is the intended insertion index */
if ( r->len >= r->maxlen )
{
r->len = r->maxlen;
new_len = max(2*r->maxlen+1,5);
if (mem_info_is_on()) {
mem_bytes(TYPE_SPROW,r->maxlen*sizeof(row_elt),
new_len*sizeof(row_elt));
}
r->elt = RENEW(r->elt,new_len,row_elt);
if ( ! r->elt ) /* can't allocate */
error(E_MEM,"sprow_set_val");
r->maxlen = 2*r->maxlen+1;
}
for ( idx2 = r->len-1; idx2 >= idx; idx2-- )
MEM_COPY((char *)(&(r->elt[idx2])),
(char *)(&(r->elt[idx2+1])),sizeof(row_elt));
/************************************************************
if ( idx < r->len )
MEM_COPY((char *)(&(r->elt[idx])),(char *)(&(r->elt[idx+1])),
(r->len-idx)*sizeof(row_elt));
************************************************************/
r->len++;
r->elt[idx].col = j;
r->elt[idx].nxt_row = -1;
r->elt[idx].nxt_idx = -1;
return r->elt[idx].val = val;
}
/* else -- idx == -1, error in index/matrix! */
return 0.0;
}